/**
 * 1.这是我们书写的第一个文件，先来实现数据劫持，就是给对象的每个属性添加get与set
 * 这是响应式的前提
 * 2. 此文件是用来添加get与set中的代码的
 * 3. 实现深度劫持 无论传入的对象有没有嵌套 都需要给对应的属性添加劫持功能
 * 4. 此文件是用来实现数据代理  就是将传入进来的对象中的data中的值添加到vm实例对象上
 */
function Vue(options) {
  this.$data = this._data = options.data

  //1. 调用一下observe函数，实现数据劫持
  observe(this.$data)

  //2. 实现代理
  Object.keys(this.$data).forEach(key => {
    this.proxy(key)
  })
}

Vue.prototype = {
  proxy: function (key) {
    // 在构造函数的原型对象的方法中,this还是指向的构造函数的实例对象
    Object.defineProperty(this, key, {
      get() {
        return this.$data[key] // 返回原来默认值
      },
      set(value) {
        this.$data[key] = value // 将新值覆盖原值
      }
    })
  }
}

// 实现数据劫持 给对象的属性添加get与set方法
function observe(obj) {
  // 6. 进行递归时的条件判断
  if (!obj || typeof obj !== 'object') return; // 条件结束，不要向下执行了
  // 1. 先使用Object.keys获取传入进来的obj对象的所有的属性并遍历
  // Object.keys(obj) // ['msg','name','age']
  Object.keys(obj).forEach(key => {
    // 3. 先将对象属性中的原来的值保留到一个变量当中
    let origineValue = obj[key] //
    // 5. 进行递归调用 实现深度劫持
    observe(origineValue)
    // 2. 给每一个属性添加get与set方法
    Object.defineProperty(obj, key, {
      // 4. 给每个属性的get与set函数中添加代码 实现劫持
      get() {
        return origineValue
      },
      set(value) {
        origineValue = value
      }
    })
  })
}


// const vm = new Vue({
//   el: '#app',
//   data: {
//     msg: 'hello vue',
//     name: 'jack',
//     age:20
//   }
// })